home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 90 / CD Actual 90.iso / Software3D / K-3D / k3d-0.4.2.1 / shaders / k3d_uberlight.sl < prev    next >
Encoding:
Text File  |  2004-07-23  |  21.2 KB  |  526 lines

  1. /****************************************************************************
  2.  * uberlight.sl - a light with many fun controls.
  3.  *
  4.  * Description:
  5.  *   Based on Ronen Barzel's paper "Lighting Controls for Computer
  6.  *   Cinematography" (in Journal of Graphics Tools, vol. 2, no. 1: 1-20).
  7.  *
  8.  * Rather than explicitly pass "from" and "to" points to indicate the
  9.  * position and direction of the light (as spotlight does), this light
  10.  * emits from the origin of the local light shader space and points
  11.  * toward the +z axis (also in shader space).  Thus, to position and
  12.  * orient the light source, you must translate and rotate the
  13.  * coordinate system in effect when the light source is declared.
  14.  * Perhaps this is a new idea for some users, but it isn't really
  15.  * hard, and it vastly simplifies the math in the shader.
  16.  *
  17.  * Basic color/brightness controls:
  18.  *   intensity - overall intensity scaling of the light
  19.  *   lightcolor - overall color filtering for the light
  20.  *
  21.  * Light type:
  22.  *   lighttype - one of "spot", "omni", or "arealight".  Spot lights are
  23.  *       those that point in a particular direction (+z in local light
  24.  *       space, for this light).  Omni lights throw light in all directions.
  25.  *       Area lights are emitted from actual geometry (this only works on
  26.  *       BMRT area lights for the time being).
  27.  *
  28.  * Distance shaping and falloff controls:
  29.  *   cuton, cutoff - define the depth range (z range from the origin, in
  30.  *       light coordinates) over which the light is active.  Outside
  31.  *       this range, no energy is transmitted.
  32.  *   nearedge, faredge - define the width of the transition regions
  33.  *       for the cuton and cutoff.  The transitions will be smooth.
  34.  *   falloff - defines the exponent for falloff.  A falloff of 0 (the
  35.  *       default) indicates that the light is the same brightness
  36.  *       regardless of distance from the source.  Falloff==1 indicates
  37.  *       linear (1/r) falloff, falloff==2 indicates 1/r^2 falloff
  38.  *       (which is physically correct for point-like sources, but
  39.  *       sometimes hard to use).
  40.  *   falloffdist - the distance at which the incident energy is actually
  41.  *       equal to intensity*lightcolor.  In other words, the intensity
  42.  *       is actually given by:   I = (falloffdist / distance) ^ falloff
  43.  *   maxintensity - to prevent the light from becoming unboundedly
  44.  *       large when the distance < falloffdist, the intensity is
  45.  *       smoothly clamped to this maximum value.
  46.  *   parallelrays - when 0 (the default), the light appears to emanate
  47.  *       from a single point (i.e., the rays diverge).  When nonzero, 
  48.  *       the light rays are parallel, as if from an infinitely distant
  49.  *       source (like the sun).
  50.  *
  51.  * Shaping of the cross-section.  The cross-section of the light cone
  52.  * is actually described by a superellipse with the following
  53.  * controls:
  54.  *   shearx, sheary - define the amount of shear applied to the light
  55.  *       cone direction.  Default is 0, meaning that the center of the
  56.  *       light cone is aligned with the z-axis in local light space.
  57.  *   width, height - define the dimensions of the "barn door" opening.
  58.  *       They are the cross-sectional dimensions at a distance of 1
  59.  *       from the light.  In other words, width==height==1 indicates a
  60.  *       90 degree cone angle for the light.
  61.  *   wedge, hedge - the amount of width and height edge fuzz,
  62.  *       respectively.  Values of 0 will make a sharp cutoff, larger
  63.  *       values (up to 1) will make the edge softer.
  64.  *   roundness - controls how rounded the corners of the superellipse
  65.  *       are.  If this value is 0, the cross-section will be a perfect
  66.  *       rectangle.  If the value is 1, the cross-section will be a
  67.  *       perfect ellipse.  In-between values control the roundness of
  68.  *       the corners in a fairly obvious way.
  69.  *   beamdistribution - controls intensity falloff due to angle.
  70.  *       A value of 0 (the default) means no angle falloff.  A value
  71.  *       of 1 is roughly physically correct for a spotlight and 
  72.  *       corresponds to a cosine falloff.  For a BMRT area light, the
  73.  *       cosine falloff happens automatically, so 0 is the right physical
  74.  *       value to use.  In either case, you may use larger values to
  75.  *       make the spot more bright in the center than the outskirts.
  76.  *       This parameter has no effect for omni lights.
  77.  *
  78.  * Cookie or slide filter:
  79.  *   slidename - if a filename is supplied, a texture lookup will be
  80.  *       done and the light emitted from the source will be filtered
  81.  *       by that color, much like a slide projector.  If you want to
  82.  *       make a texture map that simply blocks light, just make it
  83.  *       black-and-white, but store it as an RGB texture.  For
  84.  *       simplicity, the shader assumes that the texture file will
  85.  *       have at least three channels.
  86.  *
  87.  * Projected noise on the light:
  88.  *   noiseamp - amplitude of the noise.  A value of 0 (the default) 
  89.  *       means not to use noise.  Larger values increase the blotchiness
  90.  *       of the projected noise.
  91.  *   noisefreq - frequency of the noise.
  92.  *   noiseoffset - spatial offset of the noise.  This can be animated,
  93.  *       for example, you can use the noise to simulate the
  94.  *       attenuation of light as it passes through a window with 
  95.  *       water drops dripping down it.
  96.  * 
  97.  * Shadow mapped shadows.  For PRMan (and perhaps other renderers),
  98.  * shadows are mainly computed by shadow maps.  Please consult the
  99.  * PRMan documentation for more information on the meanings of these
  100.  * parameters.
  101.  *   shadowmap - the name of the texture containing the shadow map.  If
  102.  *       this value is "" (the default), no shadow map will be used.
  103.  *   shadowblur - how soft to make the shadow edge, expressed as a
  104.  *       percentage of the width of the entire shadow map.
  105.  *   shadowbias - the amount of shadow bias to add to the lookup.
  106.  *   shadownsamps - the number of samples to use.
  107.  *
  108.  * Ray-traced shadows.  These options work only for BMRT:
  109.  *   raytraceshadow - if nonzero, cast rays to see if we are in shadow.
  110.  *       The default is zero, i.e., not to try raytracing.
  111.  *   nshadowrays - The number of rays to trace to determine shadowing.
  112.  *   shadowcheat - add this offset to the light source position.  This
  113.  *       allows you to cause the shadows to emanate as if the light
  114.  *       were someplace else, but without changing the area
  115.  *       illuminated or the appearance of highlights, etc.
  116.  *
  117.  * "Fake" shadows from a blocker object.  A blocker is a superellipse
  118.  * in 3-space which effectively blocks light.  But it's not really
  119.  * geometry, the shader just does the intersection with the
  120.  * superellipse.  The blocker is defined to lie on the x-y plane of
  121.  * its own coordinate system (which obviously needs to be defined in
  122.  * the RIB file using the CoordinateSystem command).
  123.  *   blockercoords - the name of the coordinate system that defines the
  124.  *       local coordinates of the blocker.  If this is "", it indicates 
  125.  *       that the shader should not use a blocker at all.
  126.  *   blockerwidth, blockerheight - define the dimensions of the blocker's
  127.  *       superellipse shape.
  128.  *   blockerwedge, blockerhedge - define the fuzzyness of the edges.
  129.  *   blockerround - how round the corners of the blocker are (same
  130.  *       control as the "roundness" parameter that affects the light
  131.  *       cone shape.
  132.  *
  133.  * Joint shadow controls:
  134.  *   shadowcolor - Shadows (i.e., those regions with "occlusion" as
  135.  *       defined by any or all of the shadow map, ray cast, or
  136.  *       blocker) don't actually have to block light.  In fact, in
  137.  *       this shader, shadowed regions actually just change the color
  138.  *       of the light to "shadowcolor".  If this color is set to
  139.  *       (0,0,0), it effectively blocks all light.  But if you set it
  140.  *       to, say (.25,.25,.25), it will make the shadowed regions lose
  141.  *       their full brightness but not go completely dark.  Another
  142.  *       use is if you are simulating sunlight: set the lightcolor to
  143.  *       something yellowish and make the shadowcolor dark but
  144.  *       somewhat bluish.  Another effect of shadows is to set the
  145.  *       __nonspecular flag so that the shadowed regions are lit only
  146.  *       diffusely, without highlights.
  147.  * 
  148.  * Other controls:
  149.  *   nonspecular - when set to 1, this light does not create
  150.  *       specular highlights!  The default is 0, which means it makes
  151.  *       highlights just fine (except for regions in shadows, as
  152.  *       explained above).  This is very handy for lights that are
  153.  *       meant to be fill lights, rather than key lights.
  154.  *       NOTE: This depends on the surface shader looking for, and
  155.  *       correctly acting upon, this parameter.  The built-in functions
  156.  *       diffuse(), specular() and phong() all do this, for PRMan 3.5
  157.  *       and later, as well as BMRT 2.3.5 and later.  But if you write
  158.  *       your own illuminance loops in your surface shader, you've got
  159.  *       to account for it yourself.  The PRMan user manual explains how
  160.  *       to do this.
  161.  *   __nondiffuse - the analog to nonspecular; if this flag is set to
  162.  *       1, this light will only cast specular highlights but not
  163.  *       diffuse light.  This is useful for making a light that only
  164.  *       makes specular highlights, without affecting the rest of the
  165.  *       illumination in the scene.  All the same caveats apply with
  166.  *       respect to the surface shader, as described above for
  167.  *       __nonspecular.
  168.  *   __foglight - the "noisysmoke" shader distributed with BMRT will add
  169.  *       atmospheric scattering only for those lights that have this
  170.  *       parameter set to 1 (the default).  In other words, if you use
  171.  *       this light with noisysmoke, you can set this flag to 0 to
  172.  *       make a particular light *not* cause illumination in the fog.
  173.  *       Note that the noisysmoke shader is distributed with BMRT but
  174.  *       will also work just fine with PRMan (3.7 or later).
  175.  *
  176.  * NOTE: this shader has one each of: blocker, shadow map, slide, and
  177.  * noise texture.  Some advanced users may want more than one of some or
  178.  * all of these.  It is left as an exercise for the reader to make such
  179.  * extensions to the shader.
  180.  *
  181.  ***************************************************************************
  182.  *
  183.  * This shader was written as part of the course notes for ACM
  184.  * SIGGRAPH '98, course 11, "Advanced RenderMan: Beyond the Companion"
  185.  * (co-chaired by Tony Apodaca and Larry Gritz).  Feel free to use and
  186.  * distribute the source code of this shader, but please leave the
  187.  * original attribution and all comments.
  188.  *
  189.  * This shader was tested using Pixar's PhotoRealistic RenderMan 3.7
  190.  * and the Blue Moon Rendering Tools (BMRT) release 2.3.6.  I have
  191.  * tried to avoid Shading Language constructs which wouldn't work on
  192.  * older versions of these renderers, but I do make liberal use of the
  193.  * "vector" type and I often declare variables where they are used,
  194.  * rather than only at the beginning of blocks.  If you are using a
  195.  * renderer which does not support these new language features, just
  196.  * substitute "point" for all occurrances of "vector", and move the
  197.  * variable declarations to the top of the shader.
  198.  *
  199.  * Author: coded by Larry Gritz, 1998
  200.  *         based on paper by Ronen Barzel, 1997
  201.  *
  202.  * Contacts:  {lg|ronen}@pixar.com
  203.  *
  204.  *
  205.  * $Revision: 1.1 $    $Date: 2002/11/25 20:24:01 $
  206.  *
  207.  ****************************************************************************/
  208.  
  209. /* Comment out the following line if you do *not* wish to use BMRT and
  210.  * PRMan together.
  211.  */
  212. //#include "k3d_rayserver.h"
  213.  
  214.  
  215.  
  216. /* Superellipse soft clipping
  217.  * Input:
  218.  *   - point Q on the x-y plane
  219.  *   - the equations of two superellipses (with major/minor axes given by
  220.  *        a,b and A,B for the inner and outer ellipses, respectively)
  221.  * Return value:
  222.  *   - 0 if Q was inside the inner ellipse
  223.  *   - 1 if Q was outside the outer ellipse
  224.  *   - smoothly varying from 0 to 1 in between
  225.  */
  226. float clipSuperellipse(point Q;    /* Test point on the x-y plane */
  227.                float a, b;    /* Inner superellipse */
  228.                float A, B;    /* Outer superellipse */
  229.                float roundness;    /* Same roundness for both ellipses */
  230.   )
  231. {
  232.   float result = 0;
  233.   float x = abs(xcomp(Q)), y = abs(ycomp(Q));
  234.   if(x != 0 || y != 0)
  235.     {                /* avoid degenerate case */
  236.       if(roundness < 1.0e-6)
  237.     {
  238.       /* Simpler case of a square */
  239.       result = 1 - (1 - smoothstep(a, A, x)) * (1 - smoothstep(b, B, y));
  240.     }
  241.       else if(roundness > 0.9999)
  242.     {
  243.       /* Simple case of a circle */
  244.       float sqr(float x)
  245.       {
  246.         return x * x;
  247.       }
  248.       float q = a * b / sqrt(sqr(b * x) + sqr(a * y));
  249.       float r = A * B / sqrt(sqr(B * x) + sqr(A * y));
  250.       result = smoothstep(q, r, 1);
  251.     }
  252.       else
  253.     {
  254.       /* Harder, rounded corner case */
  255.       float re = 2 / roundness;    /* roundness exponent */
  256.       float q = a * b * pow(pow(b * x, re) + pow(a * y, re), -1 / re);
  257.       float r = A * B * pow(pow(B * x, re) + pow(A * y, re), -1 / re);
  258.       result = smoothstep(q, r, 1);
  259.     }
  260.     }
  261.   return result;
  262. }
  263.  
  264.  
  265.  
  266.  
  267.  
  268. /* Volumetric light shaping
  269.  * Inputs:
  270.  *   - the point being shaded, in the local light space
  271.  *   - all information about the light shaping, including z smooth depth
  272.  *     clipping, superellipse x-y shaping, and distance falloff.
  273.  * Return value:
  274.  *   - attenuation factor based on the falloff and shaping
  275.  */
  276. float ShapeLightVolume(point PL;    /* Point in light space */
  277.                string lighttype;    /* what kind of light */
  278.                vector axis;    /* light axis */
  279.                float znear, zfar;    /* z clipping */
  280.                float nearedge, faredge;
  281.                float falloff, falloffdist;    /* distance falloff */
  282.                float maxintensity;
  283.                float shearx, sheary;    /* shear the direction */
  284.                float width, height;    /* xy superellipse */
  285.                float hedge, wedge, roundness;
  286.                float beamdistribution;    /* angle falloff */
  287.   )
  288. {
  289.   /* Examine the z depth of PL to apply the (possibly smooth) cuton and
  290.    * cutoff.
  291.    */
  292.   float atten = 1;
  293.   float PLlen = length(PL);
  294.   float Pz;
  295.   if(lighttype == "spot")
  296.     {
  297.       Pz = zcomp(PL);
  298.     }
  299.   else
  300.     {
  301.       /* For omni or area lights, use distance from the light */
  302.       Pz = PLlen;
  303.     }
  304.   atten *= smoothstep(znear - nearedge, znear, Pz);
  305.   atten *= 1 - smoothstep(zfar, zfar + faredge, Pz);
  306.  
  307.   /* Distance falloff */
  308.   if(falloff != 0)
  309.     {
  310.       if(PLlen > falloffdist)
  311.     {
  312.       atten *= pow(falloffdist / PLlen, falloff);
  313.     }
  314.       else
  315.     {
  316.       float s = log(1 / maxintensity);
  317.       float beta = -falloff / s;
  318.       atten *= (maxintensity * exp(s * pow(PLlen / falloffdist, beta)));
  319.     }
  320.     }
  321.  
  322.   /* Clip to superellipse */
  323.   if(lighttype != "omni" && beamdistribution > 0)
  324.     atten *= pow(zcomp(normalize(vector PL)), beamdistribution);
  325.   if(lighttype == "spot")
  326.     {
  327.       atten *=
  328.     1 - clipSuperellipse(PL / Pz - point(shearx, sheary, 0), width,
  329.                  height, width + wedge, height + hedge,
  330.                  roundness);
  331.     }
  332.   return atten;
  333. }
  334.  
  335.  
  336.  
  337.  
  338. /* Evaluate the occlusion between two points, P1 and P2, due to a fake
  339.  * blocker.  Return 0 if the light is totally blocked, 1 if it totally
  340.  * gets through.
  341.  */
  342. float BlockerContribution(point P1, P2;
  343.               string blockercoords;
  344.               float blockerwidth, blockerheight;
  345.               float blockerwedge, blockerhedge;
  346.               float blockerround;
  347.   )
  348. {
  349.   float unoccluded = 1;
  350.   /* Get the surface and light positions in blocker coords */
  351.   point Pb1 = transform(blockercoords, P1);
  352.   point Pb2 = transform(blockercoords, P2);
  353.   /* Blocker works only if it's straddled by ray endpoints. */
  354.   if(zcomp(Pb2) * zcomp(Pb1) < 0)
  355.     {
  356.       vector Vlight = (Pb1 - Pb2);
  357.       point Pplane = Pb1 - Vlight * (zcomp(Pb1) / zcomp(Vlight));
  358.       unoccluded *=
  359.     clipSuperellipse(Pplane, blockerwidth, blockerheight,
  360.              blockerwidth + blockerwedge,
  361.              blockerheight + blockerhedge, blockerround);
  362.     }
  363.   return unoccluded;
  364. }
  365.  
  366.  
  367.  
  368.  
  369. light k3d_uberlight(
  370.              /* Basic intensity and color of the light */
  371.              string lighttype = "spot"; float intensity = 1;
  372.              color lightcolor = color(1, 1, 1);
  373.              /* Z shaping and distance falloff */
  374.              float cuton = 0.01, cutoff = 1.0e6, nearedge =
  375.              0, faredge = 0;
  376.              float falloff = 0, falloffdist = 1, maxintensity = 1;
  377.              float parallelrays = 0;
  378.              /* xy shaping of the cross-section and angle falloff */
  379.              float shearx = 0, sheary = 0;
  380.              float width = 1, height = 1, wedge = .1, hedge = .1;
  381.              float roundness = 1;
  382.              float beamdistribution = 0;
  383.              /* Cookie or slide to control light cross-sectional color */
  384.              string slidename = "";
  385.              /* Noisy light */
  386.              float noiseamp = 0, noisefreq = 4;
  387.              vector noiseoffset = 0;
  388.              /* Shadow mapped shadows */
  389.              string shadowmap = "";
  390.              float shadowblur = 0.01, shadowbias = .01, shadownsamps =
  391.              16;
  392.              color shadowcolor = 0;
  393.              /* Ray traced shadows */
  394.              float raytraceshadow = 0, nshadowrays = 1;
  395.              vector shadowcheat = vector "shader"(0, 0, 0);
  396.              /* Fake blocker shadow */
  397.              string blockercoords = "";
  398.              float blockerwidth = 1, blockerheight = 1;
  399.              float blockerwedge = .1, blockerhedge =
  400.              .1, blockerround = 1;
  401.              /* Miscellaneous controls */
  402.              float nonspecular = 0;
  403.              output varying float __nonspecular = 0;
  404.              output float __nondiffuse = 0;
  405.              output float __foglight = 1;)
  406. {
  407.   /* For simplicity, assume that the light is at the origin of shader
  408.    * space and aimed in the +z direction.  So to move or orient the
  409.    * light, you transform the coordinate system in the RIB stream, prior
  410.    * to instancing the light shader.  But that sure simplifies the
  411.    * internals of the light shader!  Anyway, let PL be the position of
  412.    * the surface point we're shading, expressed in the local light
  413.    * shader coordinates.
  414.    */
  415.   point PL = transform("shader", Ps);
  416. #ifdef BMRT
  417.   /* If it's an area light, we want the point and normal of the light
  418.    * geometry.  If not an area light, BMRT guarantees P,N will be the
  419.    * origin and z-axis of shader space.
  420.    */
  421.   point from = P;
  422.   vector axis = normalize(N);
  423. #else
  424.   /* For PRMan, we've gotta do it the hard way */
  425.   point from = point "shader"(0, 0, 0);
  426.   vector axis = normalize(vector "shader"(0, 0, 1));
  427. #endif
  428.   uniform float angle;
  429.   if(lighttype == "spot")
  430.     {                /* Spot light */
  431.       uniform float maxradius = 1.4142136 * max(height + hedge + abs(sheary),
  432.                         width + wedge + abs(shearx));
  433.       angle = atan(maxradius);
  434.     }
  435.   else if(lighttype == "arealight")
  436.     {                /* BMRT area light */
  437.       angle = PI / 2;
  438.     }
  439.   else
  440.     {                /* Omnidirectional light */
  441.       angle = PI;
  442.     }
  443.   __nonspecular = nonspecular;
  444.  
  445.   illuminate(from, axis, angle)
  446.   {
  447.     /* Accumulate attenuation of the light as it is affected by various
  448.      * blockers and whatnot.  Start with no attenuation (i.e., a 
  449.      * multiplicative attenuation of 1.
  450.      */
  451.     float atten = 1.0;
  452.     color lcol = lightcolor;
  453.  
  454.     /* Basic light shaping - the volumetric shaping is all encapsulated
  455.      * in the ShapeLightVolume function.
  456.      */
  457.     atten *=
  458.       ShapeLightVolume(PL, lighttype, axis, cuton, cutoff, nearedge, faredge,
  459.                falloff, falloffdist, maxintensity / intensity, shearx,
  460.                sheary, width, height, hedge, wedge, roundness,
  461.                beamdistribution);
  462.  
  463.     /* Project a slide or use a cookie */
  464.     if(slidename != "")
  465.       {
  466.     point Pslide = PL / point(width + wedge, height + hedge, 1);
  467.     float zslide = zcomp(Pslide);
  468.     float xslide = 0.5 + 0.5 * xcomp(Pslide) / zslide;
  469.     float yslide = 0.5 - 0.5 * ycomp(Pslide) / zslide;
  470.     lcol *= color texture(slidename, xslide, yslide);
  471.       }
  472.  
  473.     /* If the volume says we aren't being lit, skip the remaining tests */
  474.     if(atten > 0)
  475.       {
  476.     /* Apply noise */
  477.     if(noiseamp > 0)
  478.       {
  479. #pragma nolint
  480.         float n = noise(noisefreq * (PL + noiseoffset) * point(1, 1, 0));
  481.         n = smoothstep(0, 1, 0.5 + noiseamp * (n - 0.5));
  482.         atten *= n;
  483.       }
  484.  
  485.     /* Apply shadow mapped shadows */
  486.     float unoccluded = 1;
  487.     if(shadowmap != "")
  488.       unoccluded *=
  489.         1 - shadow(shadowmap, Ps, "blur", shadowblur, "samples",
  490.                shadownsamps, "bias", shadowbias);
  491.     point shadoworigin;
  492.     if(parallelrays == 0)
  493.       shadoworigin = from;
  494.     else
  495.       shadoworigin = point "shader"(xcomp(PL), ycomp(PL), cuton);
  496. #if (defined(BMRT) || defined(RAYSERVER_H))
  497.     /* If we can, apply ray cast shadows.  Force a ray trace if
  498.      * we're in BMRT and the user wanted a shadow map.
  499.      */
  500.     if(raytraceshadow != 0)
  501.       {
  502.         color vis = 0;
  503.         uniform float i;
  504.         for(i = 0; i < nshadowrays; i += 1)
  505.           vis += visibility(Ps, shadoworigin + shadowcheat);
  506.         vis /= nshadowrays;
  507.         unoccluded *= (comp(vis, 0) + comp(vis, 1) + comp(vis, 2)) / 3;
  508.       }
  509. #endif
  510.     /* Apply blocker fake shadows */
  511.     if(blockercoords != "")
  512.       {
  513.         unoccluded *=
  514.           BlockerContribution(Ps, shadoworigin, blockercoords,
  515.                   blockerwidth, blockerheight, blockerwedge,
  516.                   blockerhedge, blockerround);
  517.       }
  518.     lcol = mix(shadowcolor, lcol, unoccluded);
  519.     __nonspecular = 1 - unoccluded * (1 - __nonspecular);
  520.       }
  521.     Cl = (atten * intensity) * lcol;
  522.     if(parallelrays != 0)
  523.       L = axis * length(Ps - from);
  524.   }
  525. }
  526.